package etcd

import (
	"context"
	"crypto/tls"
	"time"

	clientv3 "go.etcd.io/etcd/client/v3"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

func NewEtcdClient(
	ctx context.Context,
	c *ETCDConf,
	tls *tls.Config,
	ops []grpc.DialOption,
	logger *zap.Logger,
	LogConfig *zap.Config,
) (*clientv3.Client, error) {
	return clientv3.New(clientv3.Config{
		Endpoints:             c.Endpoints,
		TLS:                   tls,
		AutoSyncInterval:      time.Duration(c.AutoSyncInterval),
		DialTimeout:           time.Duration(c.DialTimeout),
		DialKeepAliveTime:     time.Duration(c.DialKeepAliveTime),
		DialKeepAliveTimeout:  time.Duration(c.DialKeepAliveTimeout),
		DialOptions:           ops,
		MaxCallSendMsgSize:    int(c.MaxCallSendMsgSize * 1024 * 1024),
		MaxCallRecvMsgSize:    int(c.MaxCallRecvMsgSize * 1024 * 1024),
		Username:              c.Username,
		Password:              c.Password,
		RejectOldCluster:      c.RejectOldCluster,
		Context:               ctx,
		Logger:                logger,
		LogConfig:             LogConfig,
		PermitWithoutStream:   c.PermitWithoutStream,
		MaxUnaryRetries:       uint(c.MaxUnaryRetries),
		BackoffWaitBetween:    time.Duration(c.BackoffWaitBetween),
		BackoffJitterFraction: c.BackoffJitterFraction,
	})
}

func EtcdGet(
	ctx context.Context,
	cli *clientv3.Client,
	key string,
	ops ...clientv3.OpOption,
) (map[string]string, error) {
	rsp, err := cli.Get(ctx, key, ops...)
	if err != nil {
		return nil, err
	}
	mp := make(map[string]string, len(rsp.Kvs))
	for _, kv := range rsp.Kvs {
		mp[string(kv.Key)] = string(kv.Value)
	}
	return mp, nil
}

func EtcdPut(
	ctx context.Context,
	cli *clientv3.Client,
	key, value string,
	ops ...clientv3.OpOption,
) error {
	_, err := cli.Put(ctx, key, value, ops...)
	return err
}

func EtcdDelete(
	ctx context.Context,
	cli *clientv3.Client,
	key string,
	ops ...clientv3.OpOption,
) error {
	_, err := cli.Delete(ctx, key, ops...)
	return err
}
